package tcplib

import (
	"MqttCloudProtocolServer/ProtocolServer/mqttlib"
	"MqttCloudProtocolServer/publiclib/datamodel"
	"MqttCloudProtocolServer/publiclib/datamodel/dborm"
	"encoding/json"
	"math"
	"net"
	"strconv"
	"time"

	"gitee.com/lossage/goProtocols/modbus"
	"github.com/wonderivan/logger"
)

type MQTTReportData struct {
	Data         []uint16 `json:"data"`
	Addr         uint16   `json:"addr"`
	Regcount     uint16   `json:"regcount"`
	Funcode      uint16   `json:"funcode"`
	Regstart     uint16   `json:"regstart"`
	ReceiveFrame string   `json:"receive"` //ReceiveFrame
	Time         int      `json:"time"`
}

type MQTTReportInformation struct {
	Projectname    string            `json:"projectname"`
	Projectversion string            `json:"projectversion"`
	Fwversion      string            `json:"fwversion"`
	Cfgversion     string            `json:"cfgversion"`
	Writepoint     []string          `json:"writepoint"`
	Response       []*MQTTReportData `json:"response"`
}

//TCPServer TCP收发服务器
type ModbusServer struct {
	mqttlib.OperatorBase
	//tcp          *datamodel.TCPClient
	dbtcp     *dborm.Manageserver
	listener  net.Listener
	receiver  func(key string, buffer []uint8)
	isRunning bool
	timeout   int
	dataRam   map[uint16]map[uint16]uint16 //地址->寄存器->值
}

func (_this *ModbusServer) Start() bool {
	_this.timeout = 2000
	_this.isRunning = true
	for !_this.listenPort(_this.dbtcp.HostIP, _this.dbtcp.HostPort) {
		time.Sleep(time.Second * 5)
	}
	return true
}

//Modify Fun
func (_this *ModbusServer) Modify(params interface{}) bool {
	switch params.(type) {
	case *datamodel.TCPClient:
		//_this.tcp = params.(*datamodel.TCPClient)
		break
	case *dborm.Manageserver:
		_this.dbtcp = params.(*dborm.Manageserver)
		break
	default:
		return false
	}
	return true
}

//listenPort 监听端口
func (_this *ModbusServer) listenPort(ip string, port int) bool {
	listener, err := net.Listen("tcp", ip+":"+strconv.Itoa(int(port)))
	_this.listener = listener
	if err != nil {
		logger.Alert("server :: error listen:", err)
		return false
	}
	for _this.isRunning {
		if conn, err := _this.listener.Accept(); err != nil {
			logger.Alert("server :: accept error:", err)
			break
		} else {
			//为了不阻塞新的连接接入，采用协程接收与处理数据
			go _this.receiceData(conn)
			//_this.conns.Push(conn)
		}
	}
	return true
}

//receiceData 循环接收数据，通讯管理模式下收到数据后，内部处理，不需要返还发送给mqtt
func (_this *ModbusServer) receiceData(conn net.Conn) {
	var buffer = make([]byte, 1024)
	var retryCount = 0
	defer conn.Close()
	for _this.isRunning {
		if length, e := conn.Read(buffer); e != nil {
			if e.Error() == "EOF" {
				logger.Debug("读到EOF结束")
				retryCount = 0
				return
			}
			logger.Alert("server :: read error:", e)
			time.Sleep(time.Second)
			retryCount++
			if retryCount > 5 {
				retryCount = 0
				return
			}
		} else {
			logger.Debug("server :: read data ")
			if length < 12 {
				continue
			}
			receiveBuffer := buffer[:length]
			//logger.Alert(_this.GetKey() + ":接收到报文" + helplib.BufferToString(receiveBuffer))
			//model := new(modbus.ModbusModel)
			header := new(modbus.ModbusTCPHeader)
			header.FromArray(receiveBuffer[:6])
			//println(header)
			mmbusModel := new(modbus.ModbusModel)
			mmbusModel.Addr = receiveBuffer[6]
			mmbusModel.Command = modbus.CommandType(receiveBuffer[7])
			mmbusModel.RegNo = uint16(receiveBuffer[8])*256 + uint16(receiveBuffer[9])
			if receiveBuffer[10] != 0 {
				if _, err := conn.Write(append(header.ToArray(), receiveBuffer[6], 0x83, 0x02)); err != nil {
					logger.Alert(err)
				}
				continue
			}
			mmbusModel.RegLength = receiveBuffer[11]
			// if len(receiveBuffer) > 7 {
			// 	if _, err := conn.Write(append(header.ToArray(), receiveBuffer[6], 0x83, 0x02)); err != nil {
			// 		logger.Alert(err)
			// 	}
			// 	continue
			// }
			commandArea := uint16(0)
			switch mmbusModel.Command {
			case modbus.ReadCoilStatus: //CommandType = 1 //00001
				commandArea = 1
				//break
			case modbus.ReadInputStatus: //CommandType = 2 //10001
				commandArea = 10001
				//break
			case modbus.ReadHoldingRegisters: //CommandType = 3 //40001
				commandArea = 40001
				//break
			case modbus.ReadInputRegisters: //CommandType = 4 //30001
				commandArea = 30001
				//break
			}
			content := _this.GetDataSeque(uint16(mmbusModel.Addr), commandArea+mmbusModel.RegNo, uint16(mmbusModel.RegLength))
			if content == nil {
				if _, err := conn.Write(append(header.ToArray(), receiveBuffer[6], 0x83, 0x02)); err != nil {
					logger.Alert(err)
				}
				continue
			}
			contentLen := len(content)
			content = append(append(header.ToArray(), mmbusModel.Addr, byte(mmbusModel.Command), byte(contentLen)), content...)
			if _, err := conn.Write(content); err != nil {
				logger.Alert(err)
				continue
			}
			/*for {
				if len(_this.frameBuffer) < _this.bufferLen {
					break
				}
				<-_this.frameBuffer
			}
			if _this.isRunning {
				_this.frameBuffer <- frameObject{buffer[:length], conn, time.Now()}
			}*/
			retryCount = 0
		}
	}
}

// 获取一个序列的寄存器，返回Bytes
func (_this *ModbusServer) GetDataSeque(addr, startReg, regCount uint16) []uint8 {
	var buffer []uint8
	if startReg > 30000 && startReg < 50000 {
		buffer = make([]uint8, regCount*2)
	} else if startReg > 0 && startReg < 20000 {
		len := math.Ceil(float64(regCount) / 8)
		buffer = make([]uint8, int(len))
	} else {
		return nil
	}
	if device, ok := _this.dataRam[addr]; ok {
		for i := uint16(0); i < regCount; i++ {
			if value, ok := device[startReg+i]; ok {
				if startReg > 30000 && startReg < 50000 {
					buffer[2*i] = uint8((value & 0xff00) >> 8)
					buffer[2*i+1] = uint8(value & 0x00ff)
				} else if startReg > 0 && startReg < 20000 {
					if value != 0 {
						sit := int(math.Floor(float64(i) / 8))
						buffer[sit] = buffer[sit] | (1 << (i % 8))
					}
				} else {
					return nil
				}
			} else {
				return nil
			}
		}
		return buffer
	} else {
		return nil
	}
}

//SendData Fun Modbus管理机模式，收到数据不会主动发到TCP端口，而是内存保存数据
func (_this *ModbusServer) SendData(buffer []uint8) bool {
	logger.Trace(string(buffer))
	res := new(MQTTReportInformation)
	if err := json.Unmarshal(buffer, res); err != nil {
		logger.Alert("上报报文错误-" + err.Error())
	} else {
		datas := res.Response
		if _this.dataRam == nil {
			_this.dataRam = make(map[uint16]map[uint16]uint16)
		}
		for _, data := range datas {
			if _, ok := _this.dataRam[data.Addr]; !ok {
				_this.dataRam[data.Addr] = make(map[uint16]uint16)
			}
			for i := uint16(0); i < data.Regcount; i++ {
				if int(i) < len(data.Data) {
					_this.dataRam[data.Addr][data.Regstart+i] = data.Data[i]
				} else {
					logger.Alert("报文数据与寄存器数量不匹配-" + data.ReceiveFrame)
				}
			}
			logger.Trace(data.ReceiveFrame)
		}
		_this.checkComStatues(datas)
	}
	/*for did, device := range _this.dataRam {
		println("device addr:" + strconv.Itoa(int(did)))
		for rid, rv := range device {
			print(strconv.Itoa(int(rid)) + ":" + strconv.Itoa(int(rv)) + "|")
		}
		println("")
	}
	res := _this.GetDataSeque(1, 40001, 10)
	res = _this.GetDataSeque(1, 30001, 5)
	res = _this.GetDataSeque(1, 2, 5)
	res = _this.GetDataSeque(1, 1, 10)
	res = _this.GetDataSeque(2, 40001, 10)
	res = _this.GetDataSeque(2, 30001, 5)
	res = _this.GetDataSeque(2, 2, 5)
	res = _this.GetDataSeque(2, 1, 10)
	print(res)*/
	/*tempFrame := _this.currentFrame

	if tempFrame == nil {
		logger.Alert(_this.GetKey() + ":当前连接为空，无法发送" + helplib.BufferToString(buffer))
		return false
	} else if _this.dbtcp.Protocol == ModbusTCP  {
		if len(tempFrame.buffer) < 6 {
			logger.Alert(_this.GetKey() + ":原报文长度错误，无法判断报文头" + helplib.BufferToString(tempFrame.buffer))
			return false
		}
		var index = tempFrame.buffer[:2]
		if !_this.checkFrame(buffer, tempFrame.buffer, _this.dbtcp.Protocol) {
			logger.Alert("报文校验错误")
			return false
		}
		buffer = _this.rtu2tcpSendDeal(buffer, index)
	}
	if buffer != nil {
		if _, err := tempFrame.conn.Write(buffer); err != nil {
			logger.Alert(err)
		}
	} else {
		logger.Alert("buffer is nil")
	}
	_this.rwLocker.Done()*/
	return true
}
func (_this *ModbusServer) checkComStatues(buffer []*MQTTReportData) {
	if len(buffer) == 0 {
		return
	}
	bufferMap := make(map[uint16][]*MQTTReportData)
	for _, data := range buffer {
		if data.Funcode > 4 {
			continue
		}
		if _, ok := bufferMap[data.Addr]; !ok {
			bufferMap[data.Addr] = []*MQTTReportData{}
		}
		bufferMap[data.Addr] = append(bufferMap[data.Addr], data)
	}
	for key, value := range _this.dataRam {
		value[49999] = 0
		if _, ok := bufferMap[key]; !ok {
			bufferMap[key] = []*MQTTReportData{}
		}
		for _, data := range bufferMap[key] {
			if data.Addr == key && data.Funcode < 5 {
				if data.Data == nil || len(data.Data) == 0 { //没有数据
					if value[49999] == 0 { //依然为初始状态，置为1，表示错误无通讯
						value[49999] = 1
					} else if value[49999] == 1 { //已经发现无通讯，保持状态
						continue
					} else if value[49999] == 2 { //已经发现为2，部分寄存器丢失，保持状态
						continue
					} else if value[49999] == 0xffff { //已经发现为0xffff，之前数据正常，置为2，部分寄存器丢失
						value[49999] = 2
					}
				} else { //有数据
					if value[49999] == 0 { //依然为初始状态，置为0xffff，表示有正常报文
						value[49999] = 0xffff
					} else if value[49999] == 1 { //已经发现无通讯，置为0xffff，表示有正常报文
						value[49999] = 0x2
					} else if value[49999] == 2 { //已经发现为2，部分寄存器丢失，保持状态
						continue
					} else if value[49999] == 0xffff { //已经发现为0xffff，之前数据正常，保持
						continue
					}
				}
			}
		}
		if value[49999] == 0xffff { //最终结果为0xffff，所有数据正常，置为0
			value[49999] = 0
		}
		currentTime := time.Now()
		value[49992] = uint16(currentTime.Year())
		value[49993] = uint16(currentTime.Month())
		value[49994] = uint16(currentTime.Day())
		value[49995] = uint16(currentTime.Hour())
		value[49996] = uint16(currentTime.Minute())
		value[49997] = uint16(currentTime.Second())
		value[49998] = uint16(currentTime.Nanosecond() / 1e6)
	}
}

//SetReceive Fun
func (_this *ModbusServer) SetReceive(callback func(key string, buffer []uint8)) {
	_this.receiver = callback
}

//Close Fun
func (_this *ModbusServer) Close() bool {
	_this.isRunning = false
	/*for !_this.conns.IsEmpty() {
		conn := _this.conns.Pull().(net.Conn)
		if err := conn.Close(); err != nil {
			logger.Debug(err)
		}
	}*/
	if err := _this.listener.Close(); err != nil {
		logger.Error(err)
	}
	return true
}
